package common

import (
	"archive/tar"
	"archive/zip"
	"compress/gzip"
	"errors"
	"gitee.com/ZYqqw1150/godk/str"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

//
//  LoadEnv 加载.env配置文件
//  @Description: 加载.env配置文件
//  @param filename 配置文件路径
//  @return map[string]string 返回一个map
//  @return error 返回错误
//
func LoadEnv(filename string) (map[string]string, error) {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	pattern, err := regexp.Compile("\n|\r\n")
	if err != nil {
		return nil, err
	}

	data := make(map[string]string, 0)
	res := pattern.Split(string(bytes), -1)
	for _, v := range res {
		v = strings.TrimSpace(v)

		length := 0
		if index := strings.Index(v, "#"); index == -1 {
			length = len(v)
		} else if index == 0 {
			continue
		} else {
			length = index
		}

		v = str.Substr(v, 0, length)

		if strings.IndexRune(v, '=') != -1 {
			kv := strings.SplitN(v, "=", 2)
			if len(kv) > 0 {
				k := strings.TrimSpace(kv[0])
				v := strings.TrimSpace(kv[1])
				data[k] = v
			}
		}
	}

	return data, nil
}

//
//  FileExist
//  @Description: 判断文件是否存在
//  @param path
//  @return exist
//
func FileExist(path string) (exist bool) {
	_, err := os.Stat(path)
	if err == nil {
		exist = true
	} else if os.IsNotExist(err) {
		exist = false
	}
	return
}

//
//  FileCopy
//  @Description: 拷贝文件
//  @param src
//  @param dist
//  @return int64,error
//
func FileCopy(src, dist string) (int64, error) {
	srcFile, err := os.Open(src)
	if err != nil {
		return 0, err
	}
	defer srcFile.Close()

	distFile, err := os.Create(dist)
	if err != nil {
		return 0, err
	}
	defer distFile.Close()

	count, err := io.Copy(distFile, srcFile)
	if err != nil {
		return count, err
	}

	err = distFile.Sync()
	if err != nil {
		return 0, err
	}

	return count, nil
}

//
//  UnZipData
//  @Description: 解档zip文件
//  @param src 源文件路径
//  @param dest 解档目标路径
//  @return error
//
func UnZipData(src, dest string) error {
	zipReader, err := zip.OpenReader("./out.zip")
	if err != nil {
		return err
	}

	for _, file := range zipReader.File {
		zipFile, err := file.Open()
		if err != nil {
			return err
		}

		extractedFilePath := filepath.Join(dest, file.Name)

		dirPath := extractedFilePath
		if !file.FileInfo().IsDir() {
			i := strings.LastIndex(extractedFilePath, "\\")
			if i == -1 {
				i = strings.LastIndex(extractedFilePath, "/")
			}

			if i != -1 {
				dirPath = str.Substr(extractedFilePath, 0, i)
			}
		}

		_ = os.MkdirAll(dirPath, 0755)

		openFile, err := os.Create(extractedFilePath)
		if err != nil {
			return err
		}

		_, err = io.Copy(openFile, zipFile)
		if err != nil {
			return err
		}
	}

	return nil
}

//
//  ZipData
//  @Description: 归档zip文件
//  @param path 文件或目录
//  @return error
//
func ZipData(path string) error {
	out, err := os.Create("out.zip")
	if err != nil {
		return err
	}
	defer out.Close()

	zipWriter := zip.NewWriter(out)
	defer zipWriter.Close()

	return zipFile(path, "", zipWriter)
}

func zipFile(filePath, prefix string, zipWriter *zip.Writer) error {
	dir, err := ioutil.ReadDir(filePath)
	if err != nil {
		file, err := os.Open(filePath)
		if err != nil {
			return err
		}
		defer file.Close()

		stat, err := file.Stat()
		if err != err {
			return err
		}

		header, err := zip.FileInfoHeader(stat)
		if err != nil {
			return err
		}
		header.Name = prefix + "/" + header.Name

		fileWriter, err := zipWriter.CreateHeader(header)
		if err != nil {
			return err
		}

		_, err = io.Copy(fileWriter, file)
		if err != nil {
			return err
		}
	} else {
		for _, fs := range dir {
			d := prefix
			if fs.IsDir() {
				d = prefix + "/" + fs.Name()
			}
			err = zipFile(filePath+"/"+fs.Name(), d, zipWriter)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

//
//  UnTarData
//  @Description: 解压缩tar包
//  @param src 源文件路径
//  @param dest 解档目标路径
//  @return error
//
func UnTarData(src, dest string) error {
	open, err := os.Open(src)
	if err != nil {
		return err
	}

	gr, err := gzip.NewReader(open)
	if err != nil {
		return err
	}
	defer gr.Close()

	tr := tar.NewReader(gr)

	index := strings.LastIndex(src, "tar.gz")
	if index == -1 {
		panic(errors.New("not .tar.gz ext"))
	} else {
		dirName := string([]rune(src)[0:index])
		if dirName != "" {
			_ = os.MkdirAll(dirName, 0755)
		}
		dest = dest + dirName
	}

	for {
		h, err := tr.Next()
		if err != nil {
			if err == io.EOF {
				break
			} else {
				return err
			}
		}

		extractedFilePath := filepath.Join(dest, h.Name)
		dirPath := ""
		if !h.FileInfo().IsDir() {
			i := strings.LastIndex(extractedFilePath, "\\")
			if i == -1 {
				i = strings.LastIndex(extractedFilePath, "/")
			}

			if i != -1 {
				dirPath = str.Substr(extractedFilePath, 0, i)
			}
		}

		if dirPath != "" {
			_ = os.MkdirAll(dirPath, 0755)
		}

		create, err := os.Create(extractedFilePath)
		if err != nil {
			panic(err)
		}

		_, err = io.Copy(create, tr)
		if err != nil {
			panic(err)
		}
	}

	return nil
}

//
//  TarData
//  @Description: tar压缩文件
//  @param path 文件或目录
//  @return error
//
func TarData(path string) error {
	out, err := os.Create("out.tar.gz")
	if err != nil {
		return err
	}
	defer out.Close()

	gw := gzip.NewWriter(out)
	defer gw.Close()
	tw := tar.NewWriter(gw)

	return tarFile(path, "", tw)
}

func tarFile(filePath, prefix string, tw *tar.Writer) error {
	dir, err := ioutil.ReadDir(filePath)
	if err != nil {
		file, err := os.Open(filePath)
		if err != nil {
			return err
		}
		defer file.Close()

		stat, err := file.Stat()
		if err != err {
			return err
		}

		header, err := tar.FileInfoHeader(stat, "")
		if err != nil {
			return err
		}
		header.Name = prefix + "/" + header.Name

		err = tw.WriteHeader(header)
		if err != nil {
			return err
		}

		_, err = io.Copy(tw, file)
		if err != nil {
			return err
		}
	} else {
		for _, fs := range dir {
			d := prefix
			if fs.IsDir() {
				d = prefix + "/" + fs.Name()
			}
			err = tarFile(filePath+"/"+fs.Name(), d, tw)
			if err != nil {
				return err
			}
		}
	}

	return nil
}
